---------------------------------------------------------------------------------
  -- Design Name : Execute and Memory Access Stage
  -- File Name   : ExMemStage.vhd
  -- Function    : Execute and memory access stage
  -- Authors     : Mirko Francuski  2006/0225
  --               Milos Mihajlovic 2006/0039
  -- School      : University of Belgrade
  --               School for Electrical Engineering
  --               Department for Computer Engineering and Information Theory
  -- Subject     : VLSI Computer Systems
---------------------------------------------------------------------------------

library ieee;

use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.UserPkg.all;

entity ExMemCtrl is
  port (
    stackV      : in  std_logic;
    aluV        : in  std_logic;
    aluN        : in  std_logic;
    aluZ        : in  std_logic;
    aluC        : in  std_logic;
    wr          : in  std_logic;
    op          : in  OpCode;
    rwr         : in  RegAddr;
    r1addr      : in  RegAddr;
    r2addr      : in  RegAddr;
    stackPush   : out std_logic;
    stackPop    : out std_logic;
    aluAMUXSel  : out std_logic;
    aluBMUXSel  : out std_logic;
    stackMUXSel : out std_logic;
    dRd         : out std_logic;
    dWr         : out std_logic;
    workSignal  : in  std_logic
  );
end ExMemCtrl;

architecture behavioral of ExMemCtrl is
  signal opJump       : boolean;
  signal opBranch     : boolean;
  signal opJumpBranch : boolean;
  signal immOp        : boolean;
  signal shiftsOp     : boolean;
  signal immUseOp     : boolean;
begin

  process(all)
  begin
    if op = OPC_PUSH or op = OPC_JSR then
      stackPush <= '1';
    else
      stackPush <= '0';
    end if;
    
    if op = OPC_POP or op = OPC_RTS then
      stackPop <= '1';
    else
      stackPop <= '0';
    end if;
    
    if wr = '1' and rwr = r1addr then
      aluAMUXSel <= '1';
    else
      aluAMUXSel <= '0';
    end if;
    
    immOp    <= (op = OPC_ADDI) or (op = OPC_SUBI) or (op = OPC_MOVI);
                       
    shiftsOp <= op = OPC_SHL   or 
                op = OPC_SHR   or 
                op = OPC_SAR   or 
                op = OPC_ROL   or
                op = OPC_ROR;
                   
    immUseOp <= immOp or shiftsOp;
    
    
    if (not immUseOp) and wr = '1' and rwr = r2addr then
      aluBMUXSel <= '1';
    else
      aluBMUXSel <= '0';
    end if;    
    
    opJump <= op = OPC_JSR or op = OPC_JMP;
    opBranch <= op = OPC_BEQ or op = OPC_BNQ or op = OPC_BGE or op = OPC_BLE;
    opJumpBranch <= opJump or opBranch;
    
    -- rs1data ako je operacija PUSH
    -- newAddr ako je operacija opJumpBranch  
    if opJumpBranch then
      stackMUXSel <= '1';
    else
      stackMUXSel <= '0';
    end if;

    if op = OPC_LOAD then 
      dRd <= '1';
    else
      dRd <= '0';
    end if;
    
    if op = OPC_STORE then
      dWr <= '1';
    else
      dWr <= '0';
    end if;
    
    -- prekoracenje prilikom racunjanja adrese i u staku generise prekid
    if aluV = '1' then
      report "Warning: ALU overflow.";
    end if;
    
    if aluC = '1' then
      report "Warning: ALU carry.";
    end if;
    
    if aluZ = '1' then
      report "Info: ALU zero.";
    end if;
    
    if aluN = '1' then
      report "Info: ALU negative.";
    end if;
    
    if stackV = '1' then
      report "Interrupt: Stack overflow or underflow" severity failure;
    end if;
    
  end process;

end architecture behavioral;